﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace 反射
{
    /*  反射 : Reflection
     *  操作DLL文件的类库
     * 
     * 反射指程序可以访问、检测和修改它本身状态或行为的一种能力。 
     * 程序集包含模块，而模块包含类型，类型又包含成员。反射则提供
     * 了封装程序集、模块和类型的对象。您可以使用反射动态地创建类
     * 型的实例，将类型绑定到现有对象，或从现有对象中获取类型。然
     * 后，可以调用类型的方法或访问其字段和属性。 

    什么是元数据，什么是反射
    1.程序是用来处理数据的，文本和特性都是数据，而文明程序本身（类的定义和BLC中的类）这些也是数据。
    2.有关程序及其类型的数据被称为元数据（metadata），它们保存在程序的程序集中。
    3.程序在运行时，可以查看其他程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序的的元数据的行为叫做反射
    */

    class Program
    {
        static void Main(string[] args)
        {

            //【1】加载DLL
            Assembly assembly = Assembly.LoadFile(@"F:\projects\C#学习\Re\bin\Debug\ReflectionTest.dll");

            //【2】获取指定类型
            Type type = assembly.GetType("ReflectionTest.Hello");

            //【3-1】实例化: 动态实例化无参类     
            object Hello = Activator.CreateInstance(type);
            //【3-2】实例化: 动态实例化有参类
            object Hello2 = Activator.CreateInstance(type, new object[] { "hello" });
            //【3-3】实例化：动态实例化私有构造函数类
            object Hello3 = Activator.CreateInstance(type,true);

            //每一个类对应一个type对象，这个type对象储存了这个类， 有那些方法跟哪些数据哪些成员
            MyClass my = new();
            Type type = my.GetType();//通过对象获取这个对象所属的type
            Console.WriteLine(type.Name); //获取类的名字
            Console.WriteLine(type.Namespace); //获取命名空间
            Console.WriteLine(type.Assembly); //获取程序集
            FieldInfo[] array = type.GetFields(); //只能获取Public字段
            foreach (var item in array)
            {
                Console.WriteLine(item.Name + "");
            }
            PropertyInfo[] array2 = type.GetProperties();
            foreach (var item in array2)
            {
                Console.WriteLine(item.Name + "");
            }
            MethodInfo[] array3 = type.GetMethods();
            foreach (var item in array3)
            {
                Console.WriteLine(item.Name + "");
            }
            //通过type对象可以获取它对应的类的所有成员（public）



            Assembly assem = my.GetType().Assembly; //获取程序集
            Console.WriteLine(assem.FullName);
        }

        #region 加载DLL
        private void AssemblyLoad()
        {
            //加载DLL文件 方式一：此文件要在启动项目下
            Assembly assembly1 = Assembly.Load("ReflectionTest.dll");
            //加载DLL文件 方式二：完整路径
            Assembly assembly2 = Assembly.LoadFile(@"F:\projects\C#学习\Re\bin\Debug\ReflectionTest.dll");
            //加载DLL文件 方式三：此文件用完整路径 或者 已在启动项目的文件的文件名都行
            Assembly assembly3 = Assembly.LoadFrom("ReflectionTest.dll");

            //LoadFrom 比较好用
        }
        #endregion
        }
    }

    class MyClass
    {
        private int id;
        private int age;
        public int num;
        public string Name { get; set; }
        public void Test()
        {
            Console.WriteLine("hello");
        }
        public string Test2()
        {
            return "hello";
        }
    }
}
